#include "Graphics/ISprite.hpp"
#include "Entity/IEntity.hpp"
#include "Graphics/Colour.hpp"
#include "Math/Vector.hpp"
#include "Utility/InterfaceConversion.hpp"
#include "Utility/Singleton.hpp"

#include "SFML/Graphics/RenderWindow.hpp"
#include "SFML/Graphics/Sprite.hpp"

#include <map>
#include <string>

namespace Graphics
{
	class TextureManager
	{
	public:
		static sf::Image *Get( const std::string &path )
		{
			std::map< std::string, sf::Image * >::iterator itr = textures.find( path );

			if ( itr != textures.end() )
			{
				return itr->second;
			}
			else
			{
				sf::Image *image = new sf::Image;
				image->LoadFromFile( path );
				
				textures[ path ] = image;

				return image;
			}
		}
	private:
		static std::map< std::string, sf::Image * > textures;
	};

	std::map< std::string, sf::Image * > TextureManager::textures;

	std::list< ISprite * > ISprite::spriteList;

	ISprite::ISprite( Entity::IEntity *setEnt )
		: ent( setEnt ), renderWnd( Utility::Singleton< sf::RenderWindow >::Get() ), visible( true )
	{
		sprite.SetCenter( 0.5f, 0.5f );

		spriteList.push_back( this );
	}

	ISprite::~ISprite( void )
	{
		spriteList.remove( this );
	}

	void ISprite::Draw( void )
	{
		SetPosition( ent->GetPosition() );
		SetAngle( ent->GetAngle() );

		renderWnd->Draw( sprite );
	}

	void ISprite::Remove( void )
	{
	}

	void ISprite::LoadImage( const std::string path )
	{
		sf::Vector2f size = sprite.GetSize();

		sf::Image *img = TextureManager::Get( path );
		sprite.SetImage( *img );
		sprite.Resize( size );
		sprite.SetCenter( img->GetWidth() / 2.0f, img->GetHeight() / 2.0f );
	}

	void ISprite::FlipX( const bool flipX )
	{
		sprite.FlipX( flipX );
	}

	void ISprite::FlipY( const bool flipY )
	{
		sprite.FlipY( flipY );
	}

	Math::Vectorf ISprite::GetPosition( void ) const
	{
		return Utility::CaffVector( sprite.GetPosition() );
	}

	void ISprite::SetPosition( const Math::Vectorf &pos )
	{
		sprite.SetPosition( Utility::SFMLVector( pos ) );
	}

	float ISprite::GetAngle( void ) const
	{
		return sprite.GetRotation();
	}

	void ISprite::SetAngle( const float angle )
	{
		sprite.SetRotation( angle );
	}

	Math::Vectorf ISprite::GetSize( void ) const
	{
		return Utility::CaffVector( sprite.GetSize(), false );
	}
	
	void ISprite::SetSize( const Math::Vectorf &size )
	{
		sprite.Resize( Utility::SFMLVector( size, false ) );
	}

	Graphics::Colour ISprite::GetColour( void ) const
	{
		return Utility::CaffColour( sprite.GetColor() );
	}

	void ISprite::SetColour( const Graphics::Colour &col )
	{
		sprite.SetColor( Utility::SFMLColour( col ) );
	}

	bool ISprite::GetVisible( void ) const
	{
		return visible;
	}

	void ISprite::SetVisible( const bool vis )
	{
		visible = vis;
	}

	void ISprite::DrawAll( void )
	{
		std::list< ISprite * >::iterator itr = spriteList.begin();

		for ( ; itr != spriteList.end(); ++itr )
		{
			if ( ( *itr )->GetVisible() )
			{
				( *itr )->Draw();
			}
		}
	}
}